﻿#include"XQHttpServer.h"
#include<QTcpServer>
#include<QTcpSocket>
#include<QLocalServer>
#include<QLocalSocket>
#include<QJsonDocument>
#include<QTimer>
#include"XQFuncEventFilter.hpp"
#include"XQFuncEvent.h"
#include"XQHttpHeadRequest.h"
#include"XQHttpHeadReply.h"
#include"XQTaskPool.h"
#include"XQLog.hpp"
XQLog* XQHttpServer::m_log= XQLog::Create("XQHttpServer", LogType::Debug, XQLog::cmd_out| XQLog::cmd_cpp | XQLog::cmd_queue | XQLog::showTime);
XQHttpServer::XQHttpServer(QObject* parent)
	:XQHttpObject(parent)
{
	init();
}

XQHttpServer::~XQHttpServer()
{
	m_task->requestInterruption();
	//缓存处理
	QWriteLocker lock(&m_lock);
	for (auto& buff:m_clientBuffer)
	{
		if (buff)
			delete buff;
	}
	m_task->wait_event();
}


int XQHttpServer::timeoutConnection() const
{
	return m_timeout;
}

QString XQHttpServer::ip() const
{
	if (m_tcpServer == nullptr)
		return QString();
	QHostAddress ipAddress = m_tcpServer->serverAddress();
	QString ip = ipAddress.toString(); // 转换为字符串形式
	return ip;
}

quint16 XQHttpServer::port() const
{
	if (m_tcpServer == nullptr)
		return m_port;
	return m_tcpServer->serverPort();
}

QTcpServer* XQHttpServer::tcp() const
{
	return m_tcpServer;
}

QString XQHttpServer::serverName_local() const
{
	return m_localServerName;
}

QLocalServer* XQHttpServer::localServer() const
{
	return m_localServer;
}

XQTaskPool* XQHttpServer::taskPool() const
{
	return m_task;
}

QList<QIODevice*> XQHttpServer::clients()
{
	QReadLocker lock(&m_lock);
	return m_clientBuffer.keys();
}

bool XQHttpServer::run(NetworkType type)
{
	m_serverType = type;
	if (isTcpNetwork())
	{
		if(m_tcpServer==nullptr)
		{
			m_tcpServer = new  QTcpServer(this);
			connect(m_tcpServer, &QTcpServer::newConnection, this, &XQHttpServer::readyConnection, Qt::QueuedConnection);
		}
		if (m_tcpServer->isListening())
			m_tcpServer->close();
		if (!m_tcpServer->listen(m_address,m_port)) {
			if(m_debug & Http::Debug::error)
				XQHttpServerLog << QString("\t错误\t tcp服务器监听失败,端口:%1").arg(m_port);
			return false;
		}
		if (m_localServer)
		{
			m_localServer->close();
			m_localServer->deleteLater();
			m_localServer = nullptr;
		}
		if (m_debug&Http::Debug::Run)
			XQHttpServerLog << QString("\ttcp模式\t服务器:%1:%2开始运行").arg(ip()).arg(port());
	}
	else if (isLocalNetwork())
	{
		if (m_localServer == nullptr)
		{
			m_localServer = new  QLocalServer(this);
			connect(m_localServer, &QLocalServer::newConnection, this, &XQHttpServer::readyConnection, Qt::QueuedConnection);
		}
		if (m_localServer->isListening())
			m_localServer->close();
		if (!m_localServer->listen(serverName_local())) {
			if (m_debug & Http::Debug::error)
				XQHttpServerLog << QString("\t错误\t Local服务器监听失败,名字:%1").arg(serverName_local());
			return false;
		}
		if (m_tcpServer)
		{
			m_tcpServer->close();
			m_tcpServer->deleteLater();
			m_tcpServer = nullptr;
		}
		if (m_debug & Http::Debug::Run)
			XQHttpServerLog << QString("\tLocal模式\t服务器:%1开始运行").arg(serverName_local());
	}	
	return true;
}

void XQHttpServer::setPort(uint16_t port)
{
	if (m_tcpServer == nullptr)
	{
		m_port = port;
		return;
	}
	if (m_tcpServer->isListening())
		m_tcpServer->close();
	if (!m_tcpServer->listen(m_address, port)) {
		if (m_debug & Http::Debug::error)
			XQHttpServerLog << QString("\t错误\t 修改端口:%1,服务器监听失败").arg(port);
		return;
	}
}

void XQHttpServer::setServerName_local(const QString& name)
{
	m_localServerName=name;
}

void XQHttpServer::setTimeoutConnection(int msec)
{
	m_timeout = msec;
	if (m_timeout > 0)
	{//开启定时器
		if (m_timeoutTimer == nullptr)
		{
			m_timeoutTimer = new QTimer(this);
			m_timeoutTimer->callOnTimeout(this, &XQHttpServer::checkTimeoutConnection);
		}
	}
	else
	{//关闭定时器
		if (m_timeoutTimer != nullptr)
		{
			m_timeoutTimer->deleteLater();
			m_timeoutTimer = nullptr;
		}
	}
}

void XQHttpServer::setThreadPool_run(bool run)
{
	
	if (run && m_task == nullptr)
	{
		m_task = new XQTaskPool(this);
	}
	m_thread_run = run;
}

void XQHttpServer::setReplyFunc(std::function<XQHttpHeadReply(QIODevice* socket, XQHttpHeadRequest* header,const QByteArray& data)> func)
{
	m_readyFunc = func;
}

void XQHttpServer::sendSignals(const QString& name, const QVariantList& list)
{
	QJsonDocument jsonDoc = QVariantList_toJson(list);
	auto json = jsonDoc.toJson();
	auto send = [this](const QByteArray& name,const QByteArray& data)
		{
			QReadLocker lock(&m_lock);
			XQHttpHeadReply reply;
			reply.setHeader(QNetworkRequest::ContentTypeHeader, SignalsRequestHeader);
			reply.setHeader(SignalsRequestHeader,name);
			reply.setContent(data);
			for (auto socket: m_clientBuffer.keys())
			{
				this->send(socket, reply.toByteArray());
			}
		};
	if (m_thread_run)
		m_task->addTask([=] {send(name.toUtf8(), json); });
	else
		send(name.toUtf8(), json);
}

void XQHttpServer::init()
{
	installEventFilter(new XQFuncEventFilter(this));
	
}

void XQHttpServer::checkTimeoutConnection()
{
	QSet<QIODevice*> remove;
	auto curTime = QDateTime::currentDateTime();
	//检查超时
	{
		QReadLocker lock(&m_lock);
		for (auto it = m_clientTime.begin(); it != m_clientTime.end(); it++)
		{
			auto socket = it.key();
			auto& startTime = it.value();
			if (startTime.msecsTo(curTime) > m_timeout)
			{//超时了
				remove << socket;
			}
		}
	}
	//超时断开与客户端的连接
	for (auto socket : remove)
		readyDisconnect(socket);
}
void XQHttpServer::runTimeoutConnectionTimer()
{
	m_timeoutTimer->start(1000);
}
void XQHttpServer::readyConnection()
{
	QIODevice* socket = nullptr;
	if (isTcpNetwork() && m_tcpServer)
	{
		socket = m_tcpServer->nextPendingConnection();
	}
	else if (isLocalNetwork() && m_localServer)
	{
		socket = m_localServer->nextPendingConnection();
	}
	if (socket == nullptr)
		return;
	//记录套接字数据
	{
		QWriteLocker lock(&m_lock);
		if(m_clientBuffer[socket]==nullptr)
			m_clientBuffer[socket] = new QByteArray;//开辟缓冲区
		m_clientTime[socket] = QDateTime::currentDateTime();//记录时间
	}
	//断开时释放套接字
	if (isTcpNetwork())
		connect(static_cast<QTcpSocket*>(socket), &QTcpSocket::disconnected, [=] {readyDisconnect(socket); });
	else if (isLocalNetwork())
		connect(static_cast<QLocalSocket*>(socket), &QLocalSocket::disconnected, [=] {readyDisconnect(socket); });
	//读取数据
	connect(socket, &QIODevice::readyRead, [=] {readyRead(socket); });
	//检查开启定时器
	if (m_timeoutTimer && !m_timeoutTimer->isActive())
		runTimeoutConnectionTimer();
	//当前是否有可读取的数据
	if(socket->isReadable())
		readyRead(socket);
	if (m_debug&Http::Debug::Connection)
	{
		QString info;
		if (isTcpNetwork() && m_tcpServer)
			info= QString("\tTcp模式\t新的网络客户端连接 %1 当前数量%2").arg(hostPort(static_cast<QTcpSocket*>(socket))).arg(m_clientBuffer.size());
		else if (isLocalNetwork() && m_localServer)
			info= QString("\tLocal模式\t新的本地客户端连接 当前数量%2").arg(m_clientBuffer.size());
		XQHttpServerLog << info;
	}
	emit connected(socket);
}
void XQHttpServer::readyDisconnect(QIODevice* socket)
{
	QWriteLocker lock(&m_lock);
	if (socket == nullptr|| !m_clientBuffer.contains(socket))
		return;
	emit disconnected(socket);
	//先释放缓存
	if (m_clientBuffer[socket])
		delete m_clientBuffer[socket];
	m_clientBuffer.remove(socket);
	socket->deleteLater();
	m_clientTime.remove(socket);
	//无客户端时关闭超时定时器轮询
	if (m_clientBuffer.isEmpty() && m_timeoutTimer)
		new XQFuncEvent([=] {if(m_timeoutTimer)m_timeoutTimer->stop(); });
	if (m_debug & Http::Debug::Disconnect)
	{
		if(isTcpNetwork())
			XQHttpServerLog <<"\tTcp模式"<<hostPort(static_cast<QAbstractSocket*>(socket)) << "客户端断开连接当前剩余数量" << m_clientBuffer.size();
		else if (isLocalNetwork())
			XQHttpServerLog <<"\tLocal模式\t客户端断开连接当前剩余数量" << m_clientBuffer.size();
	}
}

void XQHttpServer::readyRead(QIODevice* socket)
{
	auto Parse = [=](QIODevice* socket) {
		QReadLocker lock(&m_lock);
		if (!m_clientBuffer.contains(socket))
			return;
		QByteArray*	data = m_clientBuffer[socket];
		//XQHttpServerLog << "接收数据";
		data->append(socket->readAll());

		//判断请求头是否完整
		auto nSel = data->indexOf("\r\n\r\n");
		while (nSel != -1)
		{
			auto startIndex = nSel + 4;//内容开始的索引
			//解析请求头和内容
			auto Header = data->left(startIndex);
			XQHttpHeadRequest head(Header);
			//判断内容是否完全读取处理完成
			if (!isReadContentFinish(head, *data, startIndex))
				return;
			//数据完全读取完毕开始解析
			size_t len = head.contentLength();
			head.setContent(data->mid(startIndex, len));
			auto& content = head.content();
			//缓存清理
			data->remove(0, len + startIndex);
			nSel = data->indexOf("\r\n\r\n");//更新查找索引
			//显示请求头
			if (m_debug & Http::Debug::HeadRequest)
			{
				auto headerReady = head.header_toByteArray();
				QString info;
				if (isTcpNetwork())
					info = QString("Tcp模式 接受客户端 %2\r\nheader:\r\n%1\r\n").arg(headerReady).arg(hostPort(static_cast<QTcpSocket*>(socket)));
				else if (isLocalNetwork())
					info = QString("Local模式 接受客户端\r\nheader:\r\n%1\r\n").arg(headerReady);
				XQHttpServerLog << info;
			}
			emit headRequestRead(Header);
			handlingRequests(socket, &head, content);
		}
		lock.unlock();
		QWriteLocker L(&m_lock);
		if(m_clientTime.contains(socket))
			m_clientTime[socket] = QDateTime::currentDateTime();//更新时间
		};
	if (m_thread_run)
		m_task->addTask([=] {Parse(socket);});
	else
		Parse(socket);
}

void XQHttpServer::handlingRequests(QIODevice* socket,XQHttpHeadRequest* header, const QByteArray& data)
{
	if (ishandlingSignalsRequest(header))
	{
		auto ret = handlingSignalsRequest(header, data);
		if (!ret.isEmpty())
			send(socket, ret);
	}
	else
	{
		XQHttpHeadReply ready;
		if (m_readyFunc != nullptr)
		{
			ready = m_readyFunc(socket, header, data);
			send(socket, ready.toByteArray());
		}
		else//默认回复
		{
			QString text = "未设置回复！！！请调用setReadyFunc成员函数设置回复方法\r\n";
			if (isTcpNetwork())
				text+=QString("服务器 %1:%2\r\n客户端 %3").arg(this->ip()).arg(this->port()).arg(hostPort(static_cast<QTcpSocket*>(socket)));
			else if (isLocalNetwork())
				text += QString("服务器 :%1\r\n").arg(this->serverName_local());
			ready.setStatusCode(404);
			ready.setStatusInfo("Not Found");
			ready.setContent(text.toUtf8());
			send(socket, ready.toByteArray());
		}

		//套接字处理
		if (QString(header->header("Connection")).contains("close", Qt::CaseInsensitive))
		{
			socket->close();
		}
		if (m_debug & Http::Debug::HeadReply)
		{
			auto headerReady = ready.header_toByteArray();
			QString info;
			if (isTcpNetwork())
				info = QString("Tcp模式 回复客户端 %2\r\nheader:\r\n%1\r\n").arg(headerReady).arg(hostPort(static_cast<QTcpSocket*>(socket)));
			else if (isLocalNetwork())
				info = QString("Local模式 回复客户端\r\nheader:\r\n%1\r\n").arg(headerReady);
			XQHttpServerLog << info;
		}
	}
	
}


void XQHttpServer::send(QIODevice* socket, const QByteArray& data)
{
	new XQFuncEvent(this, [=] {
		auto dataLen = data.size();
		QReadLocker lock(&m_lock);
		if(m_clientBuffer.contains(socket))
		{
			auto sendLen=socket->write(data);
			if ((sendLen != dataLen) && (m_debug & Http::Debug::error))
				XQHttpServerLog << QString("\t错误\t 数据大小%1字节 实际发送%2字节").arg(dataLen).arg(sendLen);
		}
		});
}

